import { Circle } from "./Object2D.js";
import { Vector2 } from "./Vector2.js";

class PickContrls {
    constructor(object, domElement) {
        if (domElement === undefined) console.warn('PickContrls: The parameter "domElement" is now mandatory.');
        if (domElement === document) console.error('PickContrls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');

        this.domElement = domElement;
        this.domElement.style.touchAction = 'none'; // disable touch scroll
        // Set to false to disable this control
        this.enabled = true;

        // "target" sets the location of focus, where the object orbits around
        this.mouse = new Vector2();
        this.mouse_p = new Vector2();
        this.object = object
        this.rangeRadius = 150
        this._pixelRatio = 1

        // console.log(this.mouse)
        const scope = this
        // const pointers = [], pointerPositions = [], pointerRange = {}
        const pointers = {}
        this.dispose = function () {
            scope.domElement.removeEventListener('pointerdown', onPointerDown);
            scope.domElement.removeEventListener('pointercancel', onPointerCancel);
            scope.domElement.removeEventListener('wheel', onMouseWheel);

            scope.domElement.removeEventListener('pointermove', onPointerMove);
            scope.domElement.removeEventListener('pointerup', onPointerUp);

            if (scope._domElementKeyEvents !== null) {
                scope._domElementKeyEvents.removeEventListener('keydown', onKeyDown);
            }

        }

        this.setPixelRatio = function (pixelRatio) {
            this._pixelRatio = pixelRatio
        }

        function addPointer(event) {
            pointers[event.pointerId] = { 'event': event }
        }

        function onTouchStart(event) {
            // LEFT
            if (event.button === 0) {
                scope.mouse.x = event.offsetX
                scope.mouse.y = event.offsetY
            }
            const range = new Circle(event.offsetX * scope._pixelRatio, event.offsetY * scope._pixelRatio, scope.rangeRadius, 120)
            range.setAttribute('fillStyle', 'rgba(0, 0, 100, 0.09)')
            range.setAttribute('stroke', false)
            range.name = 'range'
            scope.object.add(range)
            pointers[event.pointerId]['rangeId'] = range.id
            pointers[event.pointerId]['includes'] = []

            rangeObject(event.pointerId, range)
        }

        function onMouseDown(event) {
            // LEFT
            if (event.button === 0) {
                scope.mouse.x = event.offsetX
                scope.mouse.y = event.offsetY
            }
            const _pixelRatio = 1
            const range = new Circle(event.offsetX * scope._pixelRatio, event.offsetY * scope._pixelRatio, scope.rangeRadius, 120)
            range.setAttribute('fillStyle', 'rgba(0, 0, 100, 0.09)')
            range.setAttribute('stroke', false)
            range.name = 'range'
            scope.object.add(range)
            pointers[event.pointerId]['rangeId'] = range.id
            pointers[event.pointerId]['includes'] = []

            rangeObject(event.pointerId, range)
        }

        function rangeClear(pointerId, range) {
            let renderList = []
            projectObject(scope.object, renderList)

            for (let i = 0, l = renderList.length; i < l; ++i) {
                const item = renderList[i]
                if (pointers[pointerId]['includes'].includes(item)) {
                    pointers[pointerId]['includes'].splice(pointers[pointerId]['includes'].indexOf(item), 1)
                    item.pointerDiff = new Vector2()
                    item.pointer = undefined
                }
            }
            // console.log(pointers[pointerId]['includes'])
        }

        function rangeObject(pointerId, range, pointMove = false) {

            let renderList = []
            projectObject(scope.object, renderList)

            for (let i = 0, l = renderList.length; i < l; ++i) {
                const item = renderList[i]
                if (range.position.distance(renderList[i].position) < scope.rangeRadius) {
                    if (!pointers[pointerId]['includes'].includes(item)) {
                        pointers[pointerId]['includes'].push(item)
                        item.pointerDiff = Vector2.sub(item.position, range.position)
                        item.velocity.mul(0)
                        item.force.mul(0)
                        item.pointer = range
                    }
                } else {
                    if (pointers[pointerId]['includes'].includes(item) && !pointMove) {
                        pointers[pointerId]['includes'].splice(pointers[pointerId]['includes'].indexOf(item), 1)
                        item.pointerDiff = new Vector2()
                        item.pointer = undefined
                    }
                }
            }
            // console.log(pointers[pointerId]['includes'])
        }

        function projectObject(object, renderList) {
            // if (object.visible === false) return
            if (object.name !== 'range' && !object.isScene) {
                renderList.push(object)
            }
            for (let i = 0, l = object.children.length; i < l; ++i) {
                projectObject(object.children[i], renderList)
            }
        }

        function onPointerDown(event) {
            if (scope.enabled === false) return;
            if (Object.keys(pointers).length === 0) {
                scope.domElement.setPointerCapture(event.pointerId);
                scope.domElement.addEventListener('pointermove', onPointerMove);
                scope.domElement.addEventListener('pointerup', onPointerUp);
            }

            addPointer(event);

            if (event.pointerType === 'touch') {
                onTouchStart(event);
            } else {
                onMouseDown(event);
            }

        }

        function onTouchMove(event) {
            const range = scope.object.getObjectById(pointers[event.pointerId]['rangeId'])
            range.position.x = event.offsetX * scope._pixelRatio
            range.position.y = event.offsetY * scope._pixelRatio

        }

        function onMouseMove(event) {
            if (scope.enabled === false) return;
            const range = scope.object.getObjectById(pointers[event.pointerId]['rangeId'])
            // console.log(pointers[event.pointerId])
            range.position.x = event.offsetX * scope._pixelRatio
            range.position.y = event.offsetY * scope._pixelRatio
            // pointMove=true
            rangeObject(event.pointerId, range, true)
        }

        function onPointerMove(event) {
            if (scope.enabled === false) return;

            if (event.pointerType === 'touch') {
                onTouchMove(event);
            } else {
                onMouseMove(event);
            }

        }

        function removePointer(event) {
            delete pointers[event.pointerId]
        }

        function onTouchEnd(event) {
            if (scope.enabled === false) return;
            const range = scope.object.getObjectById(pointers[event.pointerId]['rangeId'])
            rangeClear(event.pointerId, range)
            range.removeFromParent()
            delete pointers[event.pointerId]
        }

        function onMouseUp(event) {
            if (scope.enabled === false) return;
            const range = scope.object.getObjectById(pointers[event.pointerId]['rangeId'])
            rangeClear(event.pointerId, range)
            range.removeFromParent()
            delete pointers[event.pointerId]
        }

        function onPointerUp(event) {
            if (scope.enabled === false) return;
            if (event.pointerType === 'touch') {
                onTouchEnd();
            } else {
                onMouseUp(event);
            }
            removePointer(event);

            if (Object.keys(pointers).length === 0) {
                scope.domElement.releasePointerCapture(event.pointerId);
                scope.domElement.removeEventListener('pointermove', onPointerMove);
                scope.domElement.removeEventListener('pointerup', onPointerUp);
            }

        }

        function onPointerCancel(event) {
            removePointer(event);
        }

        function onMouseWheel(event) {
            if (scope.enabled === false) return
            let offset = 0
            if (event.deltaY < 0) {
                offset += 3
            } else if (event.deltaY > 0) {
                offset -= 3
            }
            Object.keys(pointers).forEach(key => {
                const rangeId = pointers[key]['rangeId']
                const range = scope.object.getObjectById(rangeId)
                range.setRadiusChange(offset)

                rangeObject(key, range)
            })
            scope.rangeRadius += offset
        }

        scope.domElement.addEventListener('pointerdown', onPointerDown);
        scope.domElement.addEventListener('pointercancel', onPointerCancel);
        scope.domElement.addEventListener('wheel', onMouseWheel, { passive: false });

    }
}

export { PickContrls }